#pragma once
#include <sfml//Graphics.hpp>
#include <vector>
#include "ResourceManagers.h"
#include <Box2D/Box2D.h>

class Entity;

class Entity
{
	friend class Scene;
public:
	Entity(Entity* Parent = NULL, const char* Name = NULL , sf::RenderWindow* renderwindow = NULL) :sName(Name)
	{
		Renderer = renderwindow;
		fScale = 1.0f;
		fRotation = 0.0f;
		Renderer = NULL;
		mImageManager = NULL;
		bEnabled = true;
		cColor = sf::Color::White;
		Parent = NULL;
		bRoot = false;
		bWorld = NULL;
	}

	//Separate Init class for loading resources/physics etc etc.
	virtual void Init(void)
	{

	}

	//Update Entity
	virtual void Update(void)
	{
	}

	//Draw Entity
	virtual void Draw(void)
	{

	}
	//Entity Cleanup
	virtual ~Entity(void)
	{

	}
	//Get Parent entity
	Entity* GetParentEntity(void) const
	{
		return nParent;
	}
	//Set Parent entity
	void SetParentEntity(Entity* NewParent)
	{
		if(NULL != nParent)
		{
			nParent->RemoveChildEntity(this);
		}
		nParent = NewParent;
	}

	//Append a Child Entity
	void AddChildEntity(Entity* ChildEntity)
	{
		if(NULL != ChildEntity)
		{
			if(NULL != ChildEntity->GetParentEntity())
			{
				ChildEntity->SetParentEntity(this);
			}
			//Pass the scene's managers and pointers and such
			//to the children
			ChildEntity->Renderer = this->Renderer;
			ChildEntity->nParent = this;
			ChildEntity->mImageManager = this->mImageManager;
			ChildEntity->bWorld = this->bWorld;

			//Init the scene entity.
			ChildEntity->Init();
			//setup managers and variables
			ChildEntity->Renderer = this->Renderer;
			ChildEntity->mImageManager = this->mImageManager;


			//init
			ChildEntity->Init();
			vChildren.push_back(ChildEntity);
		}
	}

	//Remove child entity
	void RemoveChildEntity(Entity* ChildEntity)
	{
		if(NULL != ChildEntity && !vChildren.empty())
		{
			for(size_t i = 0; i < vChildren.size(); ++i)
			{
				if(vChildren[i] == ChildEntity)
				{
					vChildren.erase(vChildren.begin() + i);
					break;
				}
			}
		}
	}

	//Get name of entity
	const char* GetEntityName(void) const
	{
		return sName;
	}

	//Get number of child entities, can be recursive
	const size_t CountChildEntitys(const bool& RecursiveCount = false) const
	{
		if(!RecursiveCount)
		{
			return(vChildren.size());
		}
		else
		{
			size_t Retval = vChildren.size();
			for(size_t i = 0; i < vChildren.size(); ++i)
			{
				Retval += vChildren[i]->CountChildEntitys(true);
			}
			return(Retval);
		}
	}

	//Get Child Entity by its name
	Entity* GetChildEntityByName(const char* SearchName)
	{
		Entity* Retval = NULL;
		if(!vChildren.empty())
		{
			for(size_t i = 0; i < vChildren.size(); ++i)
			{
				if(0 == strcmp(vChildren[i]->sName, SearchName))
				{
					Retval = vChildren[i];
					break;
				}
			}
		}
		return(Retval);
	}

	//Get Current Position
	sf::Vector2f GetPosition()
	{
		return vPosition;
	}
	//Set Current Position
	void SetPosition(sf::Vector2f newPosition)
	{
		vPosition = newPosition;
	}
	//Get Current Velocity
	sf::Vector2f GetVelocity()
	{
		return vVelocity;
	}
	//Offset current position
	void Move(sf::Vector2f offset)
	{
		vPosition += offset;
	}

	//Get Entity scale
	float GetScale()
	{
		return fScale;
	}
	//Set Entity Scale
	void SetScale(float newScale)
	{
		fScale = newScale;
	}

	//Get Entity Rotation
	float GetRotation()
	{
		return fRotation;
	}
	//Set Rotation
	void SetRotation(float newRotation)
	{
		fRotation = newRotation;
	}

	//Get Entity Color
	sf::Color GetColor()
	{
		return cColor;
	}
	//Set Entity Color
	void SetColor(sf::Color newColor)
	{
		cColor = newColor;
	}


protected:
	//Parent entity
	Entity* nParent;
	//Entity Name
	const char* sName;
	//Children
	std::vector<Entity*> vChildren;

	//Color
	sf::Color cColor;
	//Position
	sf::Vector2f vPosition;
	//Velocity
	sf::Vector2f vVelocity;
	//Rotation
	float fRotation;
	//Scale
	float fScale;

	//Enable Entity
	bool bEnabled;

	//Is entity a root entity?
	bool bRoot;

	//Pointer to renderer
	//Used for drawing
	sf::RenderWindow * Renderer;

	//Pointer to Box2D world
	//Used for Physics related stuff
	b2World* bWorld;

	//Pointer to Image manager
	//Used for managing resources
	ImageManager * mImageManager;
};